//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "Base/Include/Common.h"
#include "Base/Utils/Time/TimeProfiler.h"
#include "Base/Platform/Device.h"

namespace Engine
{
namespace Base
{
	
	//
	// Event System Event
	//

	namespace ESystemEvent
	{
		enum type
		{
			NONE		= 0,

			// system //
			UPDATE,				// update (and redraw)
			RAW_TOUCH,			// finger touch event
			RAW_KEY,			// key up/down event
			TEXT_INPUT,			// text input on EditText control
			ACCEL,				// acceleration
			GYROSCOPE,			// device rotation speed in radians per second
			ORIENTATION,		// orientation changed
			ROTATION,			// rotation changed
			LOCATION,			// GPS position
			LOCATION_STATUS,	// GPS status changed
			LIGHT_SENSOR,		// ambient light
			PROXIMITY_SENSOR,	// proximity distance
			NETWORK,			// network status
			MAGNETIC,			// magnetic fields
			HARDWARE,			// keyboard and other
			WINDOW,				// window events
			APPLICATION,		// application events
			AUDIO,				// audio events
			_SYSTEM,			// hidden system events

			// engine //
			TOUCH,				// touch state changed in Input class
			KEY,				// keys state changed in Input class
			ENGINE_IN,			// engine system input events (from platform specific code)
			ENGINE_OUT,			// engine system output events (to platform specific code)

			// other //
			CUSTOM		= 31,
			_COUNT
		};
	}



	//
	// System Event Message
	//

	struct SysEvent
	{
	// types
	public:
		typedef Time<uint64>	time_t;

		struct Update
		{
			float	timeDelta;			// in seconds
			bool	redraw;				// need redraw screen
			bool	renderAvailable;
		};

		struct RawTouch
		{
			float	x, y;
			float	pressure;
			int16	id;
			bool	pressed : 1;
			bool	motion	: 1;
		};

		struct RawKey
		{
			int		code;
			bool	pressed;
		};

		struct Touch
		{
			enum EType
			{
				TOUCH		= 1,
				MULTI_TOUCH,
				MOTION,
				GESTURE,
			};

			enum EGesture
			{
				SCALING	= 1,
				ROTATING,
			};

			EType		type;
			EGesture	gesture;

			union
			{
				int		touchIndex;			// TOUCH, MOTION
				int		lastTouchIndex;		// MULTI_TOUCH
				float	scaling;			// SCALING
				float	rotating;			// ROTATING
			};
		};

		struct Accel
		{
			float		x, y, z;
		};

		struct Gyroscope
		{
			float		x, y, z;
		};

		struct Magnetic
		{
			float		x, y, z;
		};

		struct Location
		{
			uint64		utcTime;
			double		lon,
						lat;
			float		altitude,
						accuracy,
						speed;
		};

		struct LocationStatus
		{
			enum EType
			{
				NONE,
				ENABLED,
				DISABLED,
			};

			EType	status;
		};

		struct LightSensor
		{
			float		value;	// in SI lux units
		};

		struct ProximitySensor
		{
			float		distance;
		};

		struct Orientation
		{
			union {	float	azimuth,
							x;		};
			union {	float	pitch,
							y;		};
			union {	float	roll,
							z;		};
		};

		struct Rotation
		{
			float	x, y, z;
		};

		struct Hardware
		{
			enum EType
			{
				KEYBOARD = 1,
			};

			EType		type;

			union {
				bool	hwKeyboardOpen;		// KEYBOARD
			};
		};
		
		struct Application
		{
			enum EType
			{
				NONE = 0,
				CREATED,			// after application creation (on enter to render thread)
				DESTROY,			// before aplication destroing (on exit of render thread)
				ENTER_BACKGROUND,	// pause
				ENTER_FOREGROUND,	// resume
				SURFACE_CREATED,	// after this, rendering is available
				SURFACE_DESTROYED,	// after this, rendering is not available
				LOW_MEMORY,			// application in background will be destroyed
			};

			EType	type;
			bool	completed;	// ENTER_BACKGROUND, ENTER_FOREGROUND	// state changing pending or completed
		};

		struct Audio
		{
			enum EType
			{
				NONE = 0,
				SET_FOCUS,		// load audio resources in this event
				KILL_FOCUS,		// release audio resource in this event
				PAUSE,			// pause audio and may release some resources in this event
			};

			EType	type;
		};

		struct Window
		{
			enum EType
			{
				RESIZED = 1,
				SHOWN,
				HIDDEN,
				ORIENTATION_CHANGED,
			};

			EType					type;

			int						width;			// RESIZED
			int						height;			// RESIZED

			Display::EOrientation	orientation;	// ORIENTATION_CHANGED
		};

		struct Engine
		{
			uint	type;
			uint	data[3];
		};

		struct Custom
		{
			uint	data[4];
		};
		

	private:
		typedef CompileTime::TypeList20< RawTouch,		RawKey,		Accel,		Hardware,	Location,
										 Orientation,	Custom,		Engine,		Update,		Magnetic,
										 Application,	Audio,		Window,		Gyroscope,	LightSensor,
										 Rotation,		ProximitySensor, LocationStatus
										>::type		type_list_t;
		
		struct _MaxSize
		{
			template <usize L, usize R>
			struct Op { static const usize	value = CompileTime::MinMax< usize, L, R >::max; };

			template <typename T, uint Index>
			struct Process { static const usize	value = sizeof(T); };

			static const usize	init_value = 0;
		};

		enum {
			_size = type_list_t::StaticForEach< _MaxSize, usize >::value
		};

		typedef char	max_size_t[ _size ];


	// variables
	public:
		time_t				timestamp;		// in milliseconds
		ESystemEvent::type	type;

		union {
			Update			update;
			RawTouch		rawTouch;
			RawKey			rawKey;
			Accel			accel;
			Magnetic		magnetic;
			Location		location;
			LocationStatus	locStatus;
			Orientation		orient;
			Rotation		rotation;
			Hardware		hardware;
			Window			window;
			Application		app;
			Audio			audio;
			Engine			engine;
			Custom			custom;
			Gyroscope		gyro;
			LightSensor		light;
			ProximitySensor	prox;
			max_size_t		_data;
		};


	// methods
	protected:
		SysEvent () : type(ESystemEvent::NONE)	{ ZeroMem( _data ); }

		SysEvent (ESystemEvent::type type, time_t timestamp = time_t()) : type(type), timestamp(timestamp)
		{
			ZeroMem( _data );
		}
	};



	template <ESystemEvent::type E>
	struct TSysEvent : SysEvent
	{
		TSysEvent () : SysEvent(E) {}

		TSysEvent (time_t timestamp) : SysEvent(E, timestamp)
		{
			STATIC_ASSERTE(
				E == ESystemEvent::UPDATE		or E == ESystemEvent::ACCEL			or
				E == ESystemEvent::ORIENTATION	or E == ESystemEvent::LOCATION		or
				E == ESystemEvent::RAW_TOUCH	or E == ESystemEvent::RAW_KEY		or
				E == ESystemEvent::MAGNETIC		or E == ESystemEvent::GYROSCOPE		or
				E == ESystemEvent::LIGHT_SENSOR	or E == ESystemEvent::ROTATION		or
				E == ESystemEvent::ENGINE_IN	or E == ESystemEvent::ENGINE_OUT	or
				E == ESystemEvent::PROXIMITY_SENSOR
			);
		}
	};


}	// Base
}	// Engine
